AWS CDKで構築したSIEM on Amazon ESで、FSx for Windows File Serverのファイルアクセス監査ログを可視化してみた
目grep ああ目grep 目grep
こんにちは、のんピ です。
皆さんは目grepや目diffは得意ですか? 私は得意です。
目grepや目diffとは、コマンドに頼らず、人力でログや設定ファイルから特定の文字列やパターン、差分を探しだす特殊スキルです。
私は一時期、ファイヤーウォールやWAF、プロキシなどの各種ログを見る機会が多かったので、目grepや目diff力がかなり鍛えられました。
しかし、目grepや目diffはかなりの集中力が必要とされます。加えて、視力を犠牲にしたにも関わらず、以下のようなデメリットがあります。
- 真心を込めて一つ一つログを見ていくので、ログ全体の傾向を掴みにくい
- 個人のスキルに大きく依存するので、情報の抜け漏れがある可能性がある
- 一朝一夕で目grepや目diffスキルを身につけること難しく、結果として負荷が特定の人に偏りがち
- 確認するべきログの量に比例して疲労が溜まる
そのログ分析の辛みから解放されるために、今回はログの可視化やセキュリティ分析をする「SIEM on Amazon Elasticsearch Service」を使ってログ分析してみようと思います。
分析対象のログは、私注目のFSx for Windows File Serverのファイルアクセス監査ログにします。
FSx for Windows File Serverのファイルアクセス監査ログについては、以下記事をご参照ください。
SIEM on Amazon ES とは
SIEM on Amazon ES とは、AWSがOSSで公開している SIEM ソリューションです。
このソリューションを利用することで、CloudTrailやVPC Flow Logs、GuardDuty、OSなどの各種ログの可視化やセキュリティ分析を行う事が可能となります。
詳しくは、以下記事をご参照ください。
SIEM on Amazon ESの特徴は以下の通りです。
- マネージメントサービスとサーバーレスのみで構成
- AWSサービス専用の正規化、ダッシュボード
- CloudFormation/CDKによるデプロイ、約20分で完了
- クラウドサービスをご利用した分だけの従量制料金
- マルチアカウント、マルチリージョン対応
抜粋: Startup.fm: SIEM on Amazon Elasticsearch Serviceでログ調査&分析を楽にしよう
FSx for Windows File Serverのファイルアクセス監査ログをSIEM on Amazon ESに取り込むには整形する必要がある
SIEM on Amazon ESに取り込むことができるログは以下のように形式が決まっています。
AWS 以外のログをログ用 S3 バケットにエクスポートすることで SIEM on Amazon ES に取り込むことができます。ファイルフォーマットはテキスト形式、JSON 形式、CSV 形式に対応しています。テキスト形式は1行ログを取り込むことができますが、複数行ログには対応していません。S3 へのエクスポートは Logstash や Fluentd のプラグインを使う方法があります。
一方で、FSx for Windows File Serverのファイルアクセス監査ログの形式は、前回の記事で紹介した通り、以下のようなXML形式です。
<Event xmlns='http://schemas.microsoft.com/win/2004/08/events/event'> <System> <Provider Name='Microsoft-Windows-Security-Auditing' Guid='{54849625-5478-4994-A5BA-3E3B0328C30D}'/> <EventID>4659</EventID> <Version>0</Version> <Level>0</Level> <Task>12800</Task> <Opcode>0</Opcode> <Keywords>0x8020000000000000</Keywords> <TimeCreated SystemTime='2021-06-09T01:58:00.304083200Z'/> <EventRecordID>287180</EventRecordID> <Correlation/> <Execution ProcessID='4' ThreadID='1720'/> <Channel>Security</Channel> <Computer>amznfsxa67gtfky.corp.non-97.net</Computer> <Security/> </System> <EventData> <Data Name='SubjectUserSid'>S-1-5-21-2080479861-2474753211-478539028-1113</Data> <Data Name='SubjectUserName'>Admin</Data> <Data Name='SubjectDomainName'>corp</Data> <Data Name='SubjectLogonId'>0xa6bf97</Data> <Data Name='ObjectServer'>Security</Data> <Data Name='ObjectType'>File</Data> <Data Name='ObjectName'>\Device\HarddiskVolume13\share\test-folder\test-file.txt</Data> <Data Name='HandleId'>0x0</Data> <Data Name='TransactionId'>{00000000-0000-0000-0000-000000000000}</Data> <Data Name='AccessList'>%%1537 %%4423 </Data> <Data Name='AccessMask'>0x10080</Data> <Data Name='PrivilegeList'>-</Data> <Data Name='ProcessId'>0x4</Data> </EventData> </Event>
XML形式はSIEM on Amazon ES に取り込むことができるファイルフォーマットに含まれていないので、S3バケットに保存する前に、テキスト形式、JSON形式、CSV形式など別のファイルフォーマットに変換してあげる必要があります。
今回は、元々のXMLが複雑なデータ構造なので、配列とオブジェクトを使えるJSON形式に変換します。
検証環境
検証を行う環境は以下の通りです。
FSx for Windows File Serverのファイルアクセス監査ログだけダッシュボードに表示させても少し寂しいので、CloudTrailとVPC Flow Logsも分析対象となるように構成します。
分析対象のログは単一のS3バケットに集約して、es-loader
と呼ばれるLambda関数でETL処理してから、Elasticsearch Serviceに保存します。
SIEM on Amazon ESのデプロイ
AWS CDKの構成
SIEM on Amazon ESのデプロイ方法は、CloudFormationを利用するパターンと、AWS CDKを利用するパターンと2つあります。
こちらの記事では、CloudFormationでデプロイをしていたので、今回はAWS CDKを使ってデプロイをしていこうと思います。
SIEM on Amazon ESをデプロイして作られるリソースは、以下の図の赤い破線で囲った箇所になります。
なお、本来はSQSキューやSNSトピック、KMSキーなども作成されますが、図をシンプルにするために省略しています。
デプロイ準備
まず、デプロイする前の準備として、GeoLite2に登録してアクセスキーを取得します。
GeoLite2はフリーでGeoIPのデータベースを提供しているサービスです。
今回の用途としては、CloudTrailや、VPC Flow Logsの送信元IPアドレスがどこの国のIPアドレスなのかを判断するために使います。
GeoLite2の登録及び、アクセスキー取得の詳細な手順については、以下記事をご参照ください。
デプロイ
それでは、SIEM on Amazon ESをAWS CDKでデプロイします。
デプロイする際は、こちらの公式ドキュメントに従いデプロイします。
1. ソースコードのクローン
ソースコードはGitHub上で管理されているので、git clone
でソースコードをクローンします。
> git clone https://github.com/aws-samples/siem-on-amazon-elasticsearch.git
Python 3.8やgit、jqなどがインストールされていない環境の場合は、こちらの公式ドキュメントに従ってインストールします。
2. 環境変数の設定
AWS CDKを実行するにあたって必要な環境変数を確認、設定します。
# 環境変数の確認 > echo $CDK_DEFAULT_ACCOUNT > echo $AWS_DEFAULT_REGION # 環境変数に意図した値が設定されていなかった場合は、環境変数の設定 > export CDK_DEFAULT_ACCOUNT=<AWS_ACCOUNT> > export AWS_DEFAULT_REGION=<AWS_REGION>
3. AWS Lambda デプロイパッケージの作成
S3バケットに収集されたログをSIEM on Amazon ESに取り込む際に、Lambda関数が使用されます。
そのLambda関数が使用するライブラリをローカルにダウンロードをして、Lambda関数のデプロイ用のパッケージを作成します。
まず、デプロイパッケージを作成するスクリプトを確認します。
> cd siem-on-amazon-elasticsearch/deployment/cdk-solution-helper/ > ls step1-build-lambda-pkg.sh step2-setup-cdk-env.sh
step1-build-lambda-pkg.sh
と、step2-setup-cdk-env.sh
があることが確認できます。
公式ドキュメントを確認すると、step1-build-lambda-pkg.sh
を実行する様です。スクリプトを実行する前に、一旦スクリプトの中身を確認してみます。
#!/bin/bash # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: MIT-0 source_template_dir="${PWD}/.." source_dir="$source_template_dir/../source" if !(type pip3 > /dev/null 2>&1); then echo "No pip3. Install python3." echo "exist!" exit fi echo "------------------------------------------------------------------------------" echo "[Packing] pip and Source Folder" echo "------------------------------------------------------------------------------" python3 -m pip install pip==20.3.3 --user function pip_zip_for_lambda () { if [ -e $1.zip ]; then echo "rm $1.zip" rm $1.zip fi cd $1 mv README.md README.md.org echo "# delete old pip version" for dir in `ls -v -r -d *.dist-info 2>/dev/null`; do echo "rm -r" $(echo "${dir}" | sed -e 's/-.*.dist-info/*/') rm -r $(echo "${dir}" | sed -e 's/-.*.dist-info/*/') done if [ -e requirements.txt ]; then python3 -m pip install -t . -r requirements.txt -U fi find . -name __pycache__ | xargs rm -fr rm -f .DS_Store #rm -fr *dist-info echo "# delete python libraries which are already installed in lambda environment" echo "rm -fr boto* aiohttp* future* urllib3* dateutil* python_dateutil* s3transfer* six*" rm -fr boto* aiohttp* future* urllib3* dateutil* python_dateutil* s3transfer* six* if [ -d requests_aws4auth ]; then mv LICENSE README.md HISTORY.md requests_aws4auth-*-info/ fi mv -f README.md.org README.md echo "cp -f $source_template_dir/../LICENSE $source_template_dir/../CODE_OF_CONDUCT.md $source_template_dir/../CONTRIBUTING.md ${source_dir}/lambda/$1/" cp -f $source_template_dir/../LICENSE $source_template_dir/../CODE_OF_CONDUCT.md $source_template_dir/../CONTRIBUTING.md ${source_dir}/lambda/$1/ echo "zip -r -9 ../$1.zip *" zip -r -9 ../$1.zip * > /dev/null echo "rm ${source_dir}/lambda/$1/LICENSE ${source_dir}/lambda/$1/CODE_OF_CONDUCT.md ${source_dir}/lambda/$1/CONTRIBUTING.md" rm ${source_dir}/lambda/$1/LICENSE ${source_dir}/lambda/$1/CODE_OF_CONDUCT.md ${source_dir}/lambda/$1/CONTRIBUTING.md cd .. } cd ${source_dir}/lambda echo 'rm -f deploy_es/dashboard.ndjson.zip' rm -f deploy_es/dashboard.ndjson.zip echo 'zip deploy_es/dashboard.ndjson.zip -jD ../saved_objects/dashboard.ndjson' zip deploy_es/dashboard.ndjson.zip -jD ../saved_objects/dashboard.ndjson echo "# start packing es_loader" pip_zip_for_lambda "es_loader" echo "# start packing deploy_es" pip_zip_for_lambda "deploy_es" echo "# start packing geoip_downloader" pip_zip_for_lambda "geoip_downloader"
17行目にpython3 -m pip install pip==20.3.3 --user
がありますね。私の環境はpipをインストール済みなので、コメントアウトしてから実行します。
実行時のログは以下の通りです。./source/lambda/
配下に各Lambda関数用のデプロイパッケージ(zipファイル)が作成されていることが確認できます。
# デプロイパッケージの作成前確認 > cd ../../source/lambda/ > ls deploy_es es_loader geoip_downloader # スクリプトのバックアップを作成 > cd ../../deployment/cdk-solution-helper/ > cp -a step1-build-lambda-pkg.sh step1-build-lambda-pkg.sh.(date +"%Y%m%d") # スクリプトの中身を書き換え > vi step1-build-lambda-pkg.sh # 変更前と変更後の差分情報の確認 > diff -u step1-build-lambda-pkg.sh.20210615 step1-build-lambda-pkg.sh --- step1-build-lambda-pkg.sh.20210615 2021-06-15 13:13:34.000000000 +0900 +++ step1-build-lambda-pkg.sh 2021-06-15 13:15:52.000000000 +0900 @@ -14,7 +14,7 @@ echo "------------------------------------------------------------------------------" echo "[Packing] pip and Source Folder" echo "------------------------------------------------------------------------------" -python3 -m pip install pip==20.3.3 --user +# python3 -m pip install pip==20.3.3 --user function pip_zip_for_lambda () { if [ -e $1.zip ]; then echo "rm $1.zip" # スクリプトを実行して、デプロイパッケージを作成 > ./step1-build-lambda-pkg.sh # デプロイパッケージの作成確認 > cd ../../source/lambda/ > ls deploy_es es_loader geoip_downloader deploy_es.zip es_loader.zip geoip_downloader.zip
4. AWS CDKのセットアップ
次にAWS CDKのセットアップをします。
公式ドキュメントを確認すると、./step2-setup-cdk-env.sh
を実行する様です。一旦スクリプトの中身を確認してみます。
#!/bin/bash # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: MIT-0 source_template_dir="$PWD/../" source_dir="$source_template_dir/../source" is_ami2=$(cat /etc/system-release 2> /dev/null | grep -oi Karoo) if [ -z $is_ami2 ]; then echo "Not AMI2." read -p "Do you realy continue? (y/N): " yn case "$yn" in [yY]*) ;; *) echo "abort." ; exit ;; esac fi if !(type pip3 > /dev/null 2>&1); then echo "No pip3. Install python3." echo "exist!" exit fi echo "python3 -m pip install boto3 --user" python3 -m pip install boto3 --user echo "Install Node.js" curl -s -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash . ~/.nvm/nvm.sh nvm install --lts node nvm alias default lts/* node -e "console.log('Running Node.js ' + process.version)" nvm use lts/* echo "Install CDK" npm install -g aws-cdk cd ${source_dir}/cdk python3 -m venv .env source .env/bin/activate python3 -m pip install -r requirements.txt BACK=$RANDOM if [ -e cdk.json ]; then mv cdk.json cdk.json.$BACK fi cp cdk.json.public.sample cdk.json cdk synth aes-siem -o ${source_template_dir}/cdk-solution-helper/cdk.out 1>/dev/null if [ -e cdk.json.$BACK ]; then mv -f cdk.json.$BACK cdk.json fi
./step2-setup-cdk-env.sh
を実行すると、以下のソフトウェアがインストールされます。なお、AWS CDKやBoto3などはグローバルでインストールされるようです。
- Node Version Manager (nvm)
- Node.js
- AWS SDK for Python (Boto3)
- AWS CDK
私はグローバルへのインストールはなるべく避けたい派なので、必要なソフトウェアを手動でインストールしていきます。
# AWS CDKのインストール > cd siem-on-amazon-elasticsearch/source/cdk > npm install aws-cdk # venvで仮想環境を作成 > python3 -m venv .env # 仮想環境をアクティベート # 私の環境ではfishを使用しているので、source .env/bin/activate.fish を実行 # 以降のSIEM on Amazon ES関係の操作は全て仮想環境上で行う > source .env/bin/activate.fish # 仮想環境に必要なパッケージをインストール > python3 -m pip install -r requirements.txt > python3 -m pip install boto3
5. SIEM on Amazon ESをパブリックアクセス (Amazon VPC 外)にデプロイ
以下コマンドで、SIEM on Amazon ESをデプロイします。
# SIEM on Amazon ES をパブリックアクセス環境にデプロイする場合のcdk.jsonを作成 > cp -a cdk.json.public.sample cdk.json # AllowedSourceIpAddresses: Amazon VPC 外に SIEM on Amazon ES をデプロイした時に、アクセスを許可するIPアドレス。複数アドレスはスペース区切り # GeoLite2LicenseKey: Maxmindのライセンスキー。IP アドレスに国情報を付与 > npx cdk deploy \ --parameters AllowedSourceIpAddresses="10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 <自端末のIPアドレス>" \ --parameters GeoLite2LicenseKey=<事前に取得したGeoLite2のライセンスキー> (中略) ✅ aes-siem Outputs: aes-siem.KibanaAdmin = aesadmin aes-siem.KibanaPassword = 4@MqyiXy aes-siem.KibanaUrl = https://search-aes-siem-xxxxxxxxxxxx.us-east-1.es.amazonaws.com/_plugin/kibana/ aes-siem.RoleDeploy = arn:aws:iam::<AWSアカウントID>:role/aes-siem-deploy-role-for-lambda Stack ARN: arn:aws:cloudformation:us-east-1:<AWSアカウントID>:stack/aes-siem/89e941d0-ce46-11eb-ab44-0abfd97085ad
20〜30分ほどでデプロイは完了し、KibanaのURLやID、パスワードが発行されます。
デプロイが完了したら、Elasticsearch Serviceのコンソールを確認してみます。以下のように、ドメインが作成されていることが確認できます。
FSx for Windows File Serverのファイルアクセス監査ログの取り込み設定
2021年6月20日時点で、SIEM on Amazon ES は以下のログを取り込むことができます。
AWS Service | Log | |
---|---|---|
セキュリティ、ID、およびコンプライアンス | AWS Security Hub | Security Hub findings GuardDuty findings Amazon Macie findings Amazon Inspector findings AWS IAM Access Analyzer findings |
セキュリティ、ID、およびコンプライアンス | AWS WAF | AWS WAF Web ACL traffic information AWS WAF Classic Web ACL traffic information |
セキュリティ、ID、およびコンプライアンス | Amazon GuardDuty | GuardDuty findings |
セキュリティ、ID、およびコンプライアンス | AWS Network Firewall | Flow logs Alert logs |
管理とガバナンス | AWS CloudTrail | CloudTrail Log Event |
ネットワーキングとコンテンツ配信 | Amazon CloudFront | Standard access log Real-time log |
ネットワーキングとコンテンツ配信 | Amazon Route 53 Resolver | VPC DNS query log |
ネットワーキングとコンテンツ配信 | Amazon Virtual Private Cloud (Amazon VPC) | VPC Flow Logs (Version5) |
ネットワーキングとコンテンツ配信 | Elastic Load Balancing | Application Load Balancer access logs Network Load Balancer access logs Classic Load Balancer access logs |
ストレージ | Amazon Simple Storage Service (Amazon S3) | access log |
データベース | Amazon Relational Database Service (Amazon RDS) (Experimental Support) |
Amazon Aurora(MySQL) Amazon Aurora(PostgreSQL) Amazon RDS for MariaDB Amazon RDS for MySQL Amazon RDS for PostgreSQL |
分析 | Amazon Managed Streaming for Apache Kafka (Amazon MSK) | Broker log |
コンピューティング | Linux OS via CloudWatch Logs |
/var/log/messages /var/log/secure |
コンテナ | Amazon Elastic Container Service (Amazon ECS) via FireLens |
Framework only |
抜粋: SIEM on Amazon Elasticsearch Service - 対応ログ
現時点では、FSx for Windows File Serverのファイルアクセス監査ログは対応していないようですね。そのため、ログの取り込みのカスタマイズを行う必要があります。
ログの取り込みのカスタマイズは、以下公式ドキュメントによると、user.ini
を作成してLambdaレイヤーでes-loader
というLambda関数に追加すれば良いようです。
SIEM on Amazon ES へのログの取り込みをカスタマイズできます。S3 バケットにエクスポートされたログを、Lambda 関数の es-loader が正規化して SIEM on Amazon ES にロードしています。デプロイされた Lambda 関数名は aes-siem-es-loader となります。この Lambda 関数 es-loader は、S3 バケットから「すべてのオブジェクト作成イベント」のイベント通知を受け取って、起動します。S3 バケットに保存されたファイル名やファイルパスから、ログの種類を特定して、ログ種類毎に定義された方法でフィールドを抽出し、Elastic Common Schema へマッピングをして、最後に SIEM on Amazon ES へインデックス名を指定してロードします。
このプロセスは設定ファイル (aws.ini) に定義された初期値に基づいています。任意の値に変えることもできます。例えば、あるログの S3 バケットへのエクスポートは初期値とは違うファイルパスにしたり、インデックス名の変更をしたり、インデックスのローテーション間隔を変更する場合等です。変更は、aws.ini を参考に user.ini を作成して項目と値を定義します。user.ini に設定した値は aws.ini よりも優先度が高く設定されており、初期値の値を内部で上書きします。
user.ini の保存は、Lambda レイヤーによる追加(推奨)か、AWS マネジメントコンソールから直接編集をしてください。SIEM on Amazon ES をアップデートすると、Lambda 関数が新しい関数に入れ替わります。Lambda レイヤーであれば独立しているので user.ini は維持されますが、AWS マネジメントコンソールから直接編集した user.ini は削除されるので、再度 user.ini を作成する必要があります。
FSx for Windows File Serverのファイルアクセス監査ログを取り込むにあたって作成したuser.ini
は以下の通りです。
# Import audit logs for FSx for Windows File Server [fsx-windows-audit-log] # Elaticseatch Serviceにアップロードした際のインデックス名 index_name = log-aws-fsx-windows-audit # S3バケットから取り込み対象のオブジェクトを判断するための文字列 # FSx for Windows File Serverのファイルアクセス監査ログは、"AWSLogs/<アカウントID>/fsx-windows-audit-log/<リージョン名>/"配下に出力するため、"fsx-windows-audit-log" s3_key = fsx-windows-audit-log # s3_keyにマッチしても無視したいオブジェクトを判断するための文字列 # Kinesis Data FirehoseがFSx for Windows File Serverのファイルアクセス監査ログを正常にJSON形式にフォーマットできない場合は、"AWSLogs/<アカウントID>/fsx-windows-audit-log/processing-failed/<リージョン名>/"配下に出力するため、"fsx-windows-audit-log/processing-failed" s3_key_ignored = fsx-windows-audit-log/processing-failed # ログフォーマット。text, json, csv, multiline を指定可能 # 今回はJSON形式なので、json file_format = json # 正規化して使う ECS(Elastic Common Schema )フィールドをスペース区切りで列挙 # 次に正規化として使うECSフィールドを key、オリジナルフィールドを value に入力 ecs = event.system.eventid event.system.version event.system.level event.system.task event.system.opcode event.system.keywords event.system.timecreated.systemtime event.system.eventrecordid event.system.correlation event.system.channel event.system.computer event.system.security event.system.eventid = Event.System.0.EventID event.system.version = Event.System.0.Version event.system.level = Event.System.0.Level event.system.task = Event.System.0.Task event.system.opcode = Event.System.0.Opcode event.system.keywords = Event.System.0.Keywords event.system.timecreated.systemtime = Event.System.0.TimeCreated.0.$$.SystemTime event.system.eventrecordid = Event.System.0.EventRecordID event.system.correlation = Event.System.0.Correlation event.system.channel = Event.System.0.Channel event.system.computer = Event.System.0.Computer event.system.security = Event.System.0.Security # @timestamp に代入する生ログのオリジナルフィールド名 timestamp_key = Event.System.0.TimeCreated.0.$$.SystemTime # timestamp と指定されたフィールドのタイムフォーマットを指定 # 代入できるのは、epoch, syslog, iso8601 # 該当がなければ Python の Datetime フォーマットで設定 timestamp_format = %Y-%m-%dT%H:%M:%S.%f%z # nano秒が含まれていれば、切り捨ててmicro秒に変換 # Windowsのイベントログはnano秒まで含まれているため、切り捨ててmicro秒に変換する必要がある timestamp_nano = True # 定数を入力したい ECS フィールドをスペース区切りで列挙 # 次に ECS フィールドを key、定数を value に入力 # Windowsの監査ログであることを絞るために設定 static_ecs = event.kind event.category event.module event.kind = event event.category = winodws event.module = audit # scriptで処理する ECS フィールドをスペース区切りで列挙 # ドキュメトで自動生成するためと、scriptのモジュールを実行させるために入力 # 実際のロジックはモジュール内で処理 # Event.EventData配下のフィールドはログによって異なるので、スクリプトで関連付ける script_ecs = event.eventdata
ここで、user.ini
の71行目のscript_ecs
について補足します。
FSx for Windows File Serverのファイルアクセス監査ログをXML形式から、JSON形式に変換すると以下のようになります。
{ "Event": { "$": { "xmlns": "http://schemas.microsoft.com/win/2004/08/events/event" }, "System": [{ "Provider": [{ "$": { "Name": "Microsoft-Windows-Security-Auditing", "Guid": "{54849625-5478-4994-A5BA-3E3B0328C30D}" } }], "EventID": ["4663"], "Version": ["1"], "Level": ["0"], "Task": ["12800"], "Opcode": ["0"], "Keywords": ["0x8020000000000000"], "TimeCreated": [{ "$": { "SystemTime": "2021-06-16T10:00:15.351449700Z" } }], "EventRecordID": ["290972"], "Correlation": [""], "Execution": [{ "$": { "ProcessID": "4", "ThreadID": "348" } }], "Channel": ["Security"], "Computer": ["amznfsx8ye6jaez.corp.non-97.net"], "Security": [""] }], "EventData": [{ "Data": [{ "_": "S-1-5-21-2210980199-3792033766-1836880630-1113", "$": { "Name": "SubjectUserSid" } }, { "_": "Admin", "$": { "Name": "SubjectUserName" } }, { "_": "corp", "$": { "Name": "SubjectDomainName" } }, { "_": "0x82b651", "$": { "Name": "SubjectLogonId" } }, { "_": "Security", "$": { "Name": "ObjectServer" } }, { "_": "File", "$": { "Name": "ObjectType" } }, { "_": "\\Device\\HarddiskVolume13\\share\\share-folder\\test - コピー - コピー", "$": { "Name": "ObjectName" } }, { "_": "0x132c", "$": { "Name": "HandleId" } }, { "_": "%%4423", "$": { "Name": "AccessList" } }, { "_": "0x80", "$": { "Name": "AccessMask" } }, { "_": "0x4", "$": { "Name": "ProcessId" } }, { "$": { "Name": "ProcessName" } }, { "_": "S:AI", "$": { "Name": "ResourceAttributes" } }] }] } } { "Event": { "$": { "xmlns": "http://schemas.microsoft.com/win/2004/08/events/event" }, "System": [{ "Provider": [{ "$": { "Name": "Microsoft-Windows-Security-Auditing", "Guid": "{54849625-5478-4994-A5BA-3E3B0328C30D}" } }], "EventID": ["4670"], "Version": ["0"], "Level": ["0"], "Task": ["13570"], "Opcode": ["0"], "Keywords": ["0x8020000000000000"], "TimeCreated": [{ "$": { "SystemTime": "2021-06-16T10:00:38.976150700Z" } }], "EventRecordID": ["291000"], "Correlation": [""], "Execution": [{ "$": { "ProcessID": "4", "ThreadID": "344" } }], "Channel": ["Security"], "Computer": ["amznfsx8ye6jaez.corp.non-97.net"], "Security": [""] }], "EventData": [{ "Data": [{ "_": "S-1-5-21-2210980199-3792033766-1836880630-1113", "$": { "Name": "SubjectUserSid" } }, { "_": "Admin", "$": { "Name": "SubjectUserName" } }, { "_": "corp", "$": { "Name": "SubjectDomainName" } }, { "_": "0x82b651", "$": { "Name": "SubjectLogonId" } }, { "_": "Security", "$": { "Name": "ObjectServer" } }, { "_": "File", "$": { "Name": "ObjectType" } }, { "_": "\\Device\\HarddiskVolume13\\share\\share-folder\\test - コピー - コピー (2)\\test\\test-text - コピー (3) - コピー - ショートカット.lnk", "$": { "Name": "ObjectName" } }, { "_": "0x8c8", "$": { "Name": "HandleId" } }, { "_": "D:AI(A;ID;0x1301bf;;;AU)(A;ID;FA;;;SY)(A;ID;FA;;;S-1-5-21-2210980199-3792033766-1836880630-1119)", "$": { "Name": "OldSd" } }, { "_": "D:AI(A;;FA;;;S-1-5-21-2210980199-3792033766-1836880630-1113)(A;;FA;;;SY)(A;;0x1200a9;;;S-1-5-5-0-598823)", "$": { "Name": "NewSd" } }, { "_": "0x4", "$": { "Name": "ProcessId" } }, { "$": { "Name": "ProcessName" } }] }] } }
104行目までの最初のイベントには、104行目以降のイベントにはある"Name": "OldSd"
や、"Name": "NewSd"
といったオブジェクトがないことが確認できると思います。
このようにファイルアクセス監査ログはイベントによって、Event.EventData
配下に存在するキーは異なります。
このようなイベントによって動的に変化するレコードについては、script_ecs
を使用します。
script_ecs
に指定したフィールドは、Pythonで記述されたスクリプトによって処理をさせた値を関連付けることができます。例えば、|
や、スペース
で区切られているメッセージから、情報を抽出するなどです。
今回作成したスクリプトは以下の通りです。フィールドがevent.eventdata.
の形式になるように処理をします。
def transform(logdata): if not 'eventdata' in logdata['event']: logdata['event']['eventdata'] = {} eventData = logdata['Event']['EventData'][0]['Data'] for data in eventData: index = data['$']['Name'].lower() value = repr(data[next(iter(data))]) logdata['event']['eventdata'][index] = value return logdata
logdata
という辞書には、S3バケットから読み取ったログが辞書型で保存されています。
例えば、logdata['Event']['EventData'][0]['Data']
は、JSONでいうEvent.EventData.0.Data
を指しています。
スクリプト内ではlogdata['event']['eventdata']
という辞書の配下に、Event.EventData.0.Data.$.Name
というキーとそのキーに関連付く値を辞書型で保存していきます。
なお、以下公式ドキュメントに記載がある通り、スクリプトの名前には命名規約があります。
ファイル名は sf_ログの種類.py としてください。この例では、sf_apache.py となります。「ログの種類」に - (ダッシュ)が含まれている場合には、_ (アンダーバー)に置換してください。例) ログの種類: cloudfront-realtime => ファイル名: sf_cloudfront_realtime.py
このファイルを es-loader の siem ディレクトリに保存するか、Lambda レイヤーの siem ディレクトリに保存してください。
今回、user.ini
で定義したログの種類は、fsx-windows-audit-log
です。そのため、スクリプトの名前は、sf_fsx_windows_audit_log.py
になります。
Lambdaレイヤーで、作成したuser.ini
や、sf_fsx_windows_audit_log.py
は以下のようなディレクトリ構成にしてzipで固めます。
configure-es-loader ├── siem │ └── sf_fsx_windows_audit_log.py └── user.ini
なお、今回はディレクトリの名前をconfigure-es-loader
にしましたが、こちらは命名規約はないので任意の名前で問題ありません。
zipで固める際は以下の様なコマンドを実行します。
> zip -r configure-es-loader.zip user.ini siem/ adding: user.ini (deflated 69%) adding: siem/ (stored 0%) adding: siem/sf_fsx_windows_audit_log.py (deflated 59%)
それではLambdaレイヤーを作成します。
Lambdaのコンソールからレイヤー
を選択して、レイヤーの作成
をクリックします。
レイヤーの設定をしていきます。
レイヤーの名前とスクリプトのランタイムの入力をし、先ほど作成したzipファイルをアップロードして、作成
をクリックします。
レイヤーが作成完了すると以下のようなメッセージが表示されます。
作成したLambdaレイヤーをLambda関数に関連付けます。
es-loader
のLambda関数を選択して、レイヤーの追加
をクリックします。
カスタムレイヤー
を選択して、作成したLambdaレイヤーの情報を入力し、追加
をクリックします。
Lambdaレイヤーが正しく関連付いていることを確認します。
FSx for Windows File Serverのデプロイ
AWS CDKの構成
FSx for Windows File Serverも例に漏れず、AWS CDKでデプロイします。こちらのAWS CDKでデプロイされるリソースは、以下の図の赤い破線で囲った箇所になります。
なお、検証時点のAWS CDK(ver. 1.108.1)では、FSx for Windows File Serverのファイルアクセス監査ログを設定することはできなかったので、デプロイ後手動で設定をします。
デプロイ
AWS CDKの実行環境のディレクトリの構成は以下の通りです。
> tree . ├── .gitignore ├── .npmignore ├── README.md ├── bin │ └── fsx-windows-file-server.ts ├── cdk.json ├── jest.config.js ├── lib │ └── fsx-windows-file-server-stack.ts ├── package-lock.json ├── package.json ├── src │ └── lambda │ └── functions │ ├── package-lock.json │ ├── package.json │ └── xml-convert-json.ts ├── test │ └── fsx-windows-file-server.test.ts └── tsconfig.json 6 directories, 18 files
メインで動かすのは./lib/fsx-windows-file-server-stack.ts
です。ここで全てのリソースを作成しています。
./lib/fsx-windows-file-server-stack.ts
の大まかな処理の流れは以下の通りです。
- SIEM on Amazon ESで作成したログ収集用S3バケットのARN、名前の取得と、KMSキーのARNの取得
- CloudTrailの設定
- XML形式からJSON形式に変換するLambda関数の宣言
- IAMロールの作成
- Kinesis Data Firehose用
- VPC Flow Logs用
- SSM用
- Kinesis Data Firehose配信ストリームの作成
- VPCの作成
- VPC Flow Logsの有効化
- Managed Microsoft ADのAdminユーザー用のパスワードの作成
- Managed Microsoft ADの作成
- FSx for Windows File Serverの作成
- Managed Microsoft ADのDNSSサーバー情報を元に、DHCPオプションセットの作成、VPCへの割り当て
- EC2インスタンスの作成
実際のコードは以下の通りです。
import * as cdk from "@aws-cdk/core"; import * as cloudtrail from "@aws-cdk/aws-cloudtrail"; import * as lambda from "@aws-cdk/aws-lambda"; import * as nodejs from "@aws-cdk/aws-lambda-nodejs"; import * as iam from "@aws-cdk/aws-iam"; import * as kinesisfirehose from "@aws-cdk/aws-kinesisfirehose"; import * as ec2 from "@aws-cdk/aws-ec2"; import * as secretsmanager from "@aws-cdk/aws-secretsmanager"; import * as directoryservice from "@aws-cdk/aws-directoryservice"; import * as fsx from "@aws-cdk/aws-fsx"; export class FsxWindowsFileServerStack extends cdk.Stack { constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); // Declare AWS account ID, region and stackName. const { accountId, region, stackName } = new cdk.ScopedAws(this); // ARN and Name of the S3 bucket where the logs are aggregated const logBucketArn = this.node.tryGetContext("logBucketArn"); const logBucketName = this.node.tryGetContext("logBucketName"); // KMS key Arn const kmsKeyArn = this.node.tryGetContext("kmsKeyArn"); // Enabled CloudTrail new cloudtrail.CfnTrail(this, "CloudTrail", { isLogging: true, s3BucketName: logBucketName, includeGlobalServiceEvents: true, isMultiRegionTrail: true, kmsKeyId: kmsKeyArn, }); // Lambda Function for notifying Slack of the execution results of Step Functions. const fsxWindowsFileServerAuditLogConvertJsonFunction = new nodejs.NodejsFunction( this, "FsxWindowsFileServerAuditLogConvertJsonFunction", { entry: "src/lambda/functions/xml-convert-json.ts", runtime: lambda.Runtime.NODEJS_14_X, bundling: { minify: true, }, timeout: cdk.Duration.seconds(180), } ); // Create VPC Flow Logs IAM role const flowLogsIamRole = new iam.Role(this, "FlowLogsIamRole", { assumedBy: new iam.ServicePrincipal("vpc-flow-logs.amazonaws.com"), }); // Create Delivery Stream IAM role const fsxWindowsFileServerAuditLogDeliveryStreamIamRole = new iam.Role( this, "FsxWindowsFileServerAuditLogDeliveryStreamIamRole", { assumedBy: new iam.ServicePrincipal("firehose.amazonaws.com"), } ); // Create SSM IAM role const ssmIamRole = new iam.Role(this, "SsmIamRole", { assumedBy: new iam.ServicePrincipal("ec2.amazonaws.com"), managedPolicies: [ iam.ManagedPolicy.fromAwsManagedPolicyName( "AmazonSSMManagedInstanceCore" ), ], }); // Create VPC Flow Logs IAM Policy const flowLogsIamPolicy = new iam.Policy(this, "FlowLogsIamPolicy", { statements: [ new iam.PolicyStatement({ effect: iam.Effect.ALLOW, actions: ["iam:PassRole"], resources: [flowLogsIamRole.roleArn], }), new iam.PolicyStatement({ effect: iam.Effect.ALLOW, actions: [ "logs:CreateLogStream", "logs:PutLogEvents", "logs:DescribeLogStreams", ], resources: [logBucketArn], }), ], }); // Atach VPC Flow Logs IAM Policy flowLogsIamRole.attachInlinePolicy(flowLogsIamPolicy); // Create Delivery Stream IAM Policy const fsxWindowsFileServerAuditLogDeliveryStreamIamPolicy = new iam.Policy( this, "FsxWindowsFileServerAuditLogDeliveryStreamIamPolicy", { statements: [ new iam.PolicyStatement({ effect: iam.Effect.ALLOW, actions: ["iam:PassRole"], resources: [ fsxWindowsFileServerAuditLogDeliveryStreamIamRole.roleArn, ], }), new iam.PolicyStatement({ effect: iam.Effect.ALLOW, actions: [ "s3:AbortMultipartUpload", "s3:GetBucketLocation", "s3:GetObject", "s3:ListBucket", "s3:ListBucketMultipartUploads", "s3:PutObject", ], resources: [logBucketArn, `${logBucketArn}/*`], }), new iam.PolicyStatement({ effect: iam.Effect.ALLOW, actions: [ "lambda:InvokeFunction", "lambda:GetFunctionConfiguration", ], resources: [ fsxWindowsFileServerAuditLogConvertJsonFunction.functionArn, ], }), new iam.PolicyStatement({ effect: iam.Effect.ALLOW, actions: ["kms:GenerateDataKey", "kms:Decrypt"], resources: [kmsKeyArn], conditions: { StringEquals: { "kms:ViaService": `s3.${region}.amazonaws.com`, }, StringLike: { "kms:EncryptionContext:aws:s3:arn": [`${logBucketArn}/*`], }, }, }), new iam.PolicyStatement({ effect: iam.Effect.ALLOW, actions: ["logs:PutLogEvents"], resources: [ `arn:aws:logs:${region}:${accountId}:log-group:/aws/kinesisfirehose/*:log-stream:*`, ], }), ], } ); // Atach VPC Flow Logs IAM Policy fsxWindowsFileServerAuditLogDeliveryStreamIamRole.attachInlinePolicy( fsxWindowsFileServerAuditLogDeliveryStreamIamPolicy ); // Create Delivery Stream for FSx for Windows File Server audit-log to S3 Bucket const fsxWindowsFileServerAuditLogDeliveryStream = new kinesisfirehose.CfnDeliveryStream( this, "FsxWindowsFileServerAuditLogDeliveryStream", { deliveryStreamName: `aws-fsx-windows-audit-log-${stackName}`, deliveryStreamType: "DirectPut", extendedS3DestinationConfiguration: { bucketArn: logBucketArn, roleArn: fsxWindowsFileServerAuditLogDeliveryStreamIamRole.roleArn, compressionFormat: "GZIP", prefix: `AWSLogs/${accountId}/fsx-windows-audit-log/${region}/`, processingConfiguration: { enabled: true, processors: [ { type: "Lambda", parameters: [ { parameterName: "LambdaArn", parameterValue: fsxWindowsFileServerAuditLogConvertJsonFunction.functionArn, }, ], }, ], }, }, } ); // Create VPC const vpc = new ec2.Vpc(this, "Vpc", { cidr: "10.0.0.0/16", enableDnsHostnames: true, enableDnsSupport: true, natGateways: 2, maxAzs: 2, subnetConfiguration: [ { name: "Public", subnetType: ec2.SubnetType.PUBLIC, cidrMask: 24 }, { name: "Private", subnetType: ec2.SubnetType.PRIVATE, cidrMask: 24 }, ], }); // Setting VPC Flow Logs new ec2.CfnFlowLog(this, "FlowLogToLogs", { resourceId: vpc.vpcId, resourceType: "VPC", trafficType: "ALL", deliverLogsPermissionArn: flowLogsIamRole.roleArn, logDestination: logBucketArn, logDestinationType: "s3", logFormat: "${version} ${account-id} ${interface-id} ${srcaddr} ${dstaddr} ${srcport} ${dstport} ${protocol} ${packets} ${bytes} ${start} ${end} ${action} ${log-status} ${vpc-id} ${subnet-id} ${instance-id} ${tcp-flags} ${type} ${pkt-srcaddr} ${pkt-dstaddr} ${region} ${az-id} ${sublocation-type} ${sublocation-id} ${pkt-src-aws-service} ${pkt-dst-aws-service} ${flow-direction} ${traffic-path}", maxAggregationInterval: 60, }); // Create Security Group // Security Group for EC2 Instances const ec2InstanceSg = new ec2.SecurityGroup(this, "Ec2InstanceSg", { allowAllOutbound: true, vpc: vpc, }); // Security Group for FSx for Windows File Server const fsxWindowsFileServerSg = new ec2.SecurityGroup( this, "FsxWindowsFileServerSg", { allowAllOutbound: true, vpc: vpc, } ); fsxWindowsFileServerSg.addIngressRule( ec2InstanceSg, ec2.Port.tcp(445), "Allow SMB" ); fsxWindowsFileServerSg.addIngressRule( ec2InstanceSg, ec2.Port.tcp(5985), "Allow WinRM-HTTP" ); // Create MSAD secrets const msadSecret = new secretsmanager.Secret(this, "MsadSecret", { secretName: `${stackName}/msadSecret`, generateSecretString: { generateStringKey: "password", secretStringTemplate: '{"username": "Admin"}', passwordLength: 32, }, }); // Create MSAD const msad = new directoryservice.CfnMicrosoftAD(this, "Msad", { name: "corp.non-97.net", password: msadSecret.secretValueFromJson("password").toString(), vpcSettings: { vpcId: vpc.vpcId, subnetIds: vpc.selectSubnets({ subnetGroupName: "Private", }).subnetIds, }, edition: "Standard", }); // Create FSx for Windows File Server const fsxWindowsFileServer = new fsx.CfnFileSystem( this, "FsxWindowsFileServer", { fileSystemType: "WINDOWS", subnetIds: vpc.selectSubnets({ subnetGroupName: "Private", }).subnetIds, securityGroupIds: [fsxWindowsFileServerSg.securityGroupId], storageCapacity: 32, storageType: "SSD", windowsConfiguration: { throughputCapacity: 32, activeDirectoryId: msad.ref, automaticBackupRetentionDays: 1, copyTagsToBackups: true, dailyAutomaticBackupStartTime: "10:00", deploymentType: "MULTI_AZ_1", preferredSubnetId: vpc .selectSubnets({ subnetGroupName: "Private", availabilityZones: [vpc.availabilityZones[0]], }) .subnetIds.toString(), weeklyMaintenanceStartTime: "7:13:30", }, } ); // Create DHCP Option Set const dhcpOption = new ec2.CfnDHCPOptions(this, "DhcpOption", { domainName: msad.name, domainNameServers: msad.attrDnsIpAddresses, }); // Association of DHCP Option Set to VPC new ec2.CfnVPCDHCPOptionsAssociation(this, "DhcpOptionAssociation", { dhcpOptionsId: dhcpOption.ref, vpcId: vpc.vpcId, }); // Create EC2 Instance const ec2Instance = new ec2.Instance(this, `Ec2Instance$`, { machineImage: ec2.MachineImage.latestWindows( ec2.WindowsVersion.WINDOWS_SERVER_2019_JAPANESE_FULL_BASE ), instanceType: new ec2.InstanceType("t3.micro"), vpc: vpc, keyName: this.node.tryGetContext("key-pair"), role: ssmIamRole, vpcSubnets: vpc.selectSubnets({ subnetGroupName: "Private", }), securityGroup: ec2InstanceSg, }); } }
./lib/fsx-windows-file-server-stack.ts
の20-21行目、24行目のSIEM on Amazon ESのAWS CDKで作成されたリソースの情報は、以下のようにcdk.json
で設定します。
{ "app": "npx ts-node --prefer-ts-exts bin/fsx-windows-file-server.ts", "context": { "key-pair": "<キーペアの名前>", "logBucketArn": "<SIEM on Amazon ESのスタックで作成したログ収集用S3バケットのARN>", "logBucketName": "<SIEM on Amazon ESのスタックで作成したログ収集用S3バケットの名前>", "kmsKeyArn": "<SIEM on Amazon ESのスタックで作成したKMSキーのARN>", "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, "@aws-cdk/core:enableStackNameDuplicates": "true", "aws-cdk:enableDiffNoFail": "true", "@aws-cdk/core:stackRelativeExports": "true", "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, "@aws-cdk/aws-secretsmanager:parseOwnedSecretName": true, "@aws-cdk/aws-kms:defaultKeyPolicies": true, "@aws-cdk/aws-s3:grantWriteWithoutAcl": true, "@aws-cdk/aws-ecs-patterns:removeDefaultDesiredCount": true, "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, "@aws-cdk/aws-efs:defaultEncryptionAtRest": true, "@aws-cdk/aws-lambda:recognizeVersionProps": true } }
Kinesis Data Firehoseに送られたログファイルをXML形式からJSON形式に変換するLambda関数は以下の通りです。
改行や水平タブなど不要な情報を削除したあと、xml2js
というパッケージを使用してXML形式から、JSON形式に変換しています。
import { Context, Callback } from "aws-lambda"; import { parseString } from "xml2js"; interface Record { recordId: string; approximateArrivalTimestamp?: string; result?: string; data: string; } interface OutputRecords { records: Record[]; } // Function to convert xml to json. const xmlToJson = async (record: Record): Promise<Record> => { const payload: string = Buffer.from(record.data, "base64") .toString("utf-8") .replace(/\r?\n?\t/g, ""); console.log("Decoded payload:", payload); return new Promise((resolve, reject) => { parseString(payload, (error, result) => { if (error) { /* Failed event, notify the error and leave the record intact */ console.log(error.message); console.log("Error message:", error.message); console.log(payload); reject({ recordId: record.recordId, result: "ProcessingFailed", data: record.data, }); } else { console.log(JSON.stringify(result)); resolve({ recordId: record.recordId, result: "Ok", data: Buffer.from(JSON.stringify(result) + "\n", "utf8").toString( "base64" ), }); } }); }); }; // main exports.handler = async ( event: any, context: Context, callback: Callback ): Promise<OutputRecords> => { console.log(event); /* Process the list of records and transform them */ const output: Record[] = await Promise.all( event.records.map(async (record: Record) => { return await xmlToJson(record); }) ); console.log(`Processing completed.`); console.log("output"); console.log(output); return { records: output }; };
あとは、cdk deploy
を実行することで、各種リソースがデプロイされます。
ファイルアクセス監査ログの設定
FSx for Windows File Serverの設定
先述した通り、現時点ではAWS CDKでFSx for Windows File Serverのファイルアクセス監査ログを設定することはできなかったので、手動で設定をします。
FSxのコンソールを開き、作成されたFSx for Windows File Serverをクリックします。その後、管理
タブから、管理
をクリックします。
続いて、各ログ記録を有効にし、送信先に作成した配信ストリームを指定して保存
をクリックします。
設定が完了すると、各種ログ記録が有効になり、監査イベントログの送信先も作成した配信ストリームになっていることが確認できます。
監査エントリの追加
FSx for Windows File Serverの設定が完了したので、続いて共有フォルダーに対して監査エントリーを追加します。
最初に、Managed Microsoft ADのAdminユーザーのパスワードの確認をします。
パスワードはSecrets Managerで作成したので、Secrets Managerのコンソールを確認します。
対象のシークレットを確認すると、以下のようにパスワードが生成されています。
それでは、SSMセッションマネージャーでポートフォワーディングして、EC2インスタンスにRDP接続をします。
> aws ssm start-session --target <インスタンスID> --document-name AWS-StartPortForwardingSession --parameters portNumber=3389,localPortNumber=13389 --region <インスタンスをデプロイしたリージョン>
なお、この時点ではEC2インスタンスはドメインに参加していないので、ローカルのAdministratorユーザーでログインします。
ログイン後は、PowerShellを起動し、以下コマンドでドメインに参加します。
> Add-Computer -DomainName corp.non-97.net -Credential Admin -PassThru -Verbose -Restart
上述したコマンドを実行すると、自動でOSが再起動します。OSの再起動完了後、再度RDP接続をします。
この際は、Secrets Managerで確認したパスワードを使って、ドメインのAdminユーザーでログインします。
ドメインのAdminユーザーでログインした後は、以下コマンドで共有フォルダーをZドライブに割り当てます。
> net use Z: \\amznfsxafmmqvqp.corp.non-97.net\share
Zドライブに割り当てた共有フォルダー上で、PowerShellを起動します。
以下コマンドで、共有フォルダ配下にshare-folder
というフォルダーを作成して、そのフォルダーに監査エントリーを追加します。
# share-folderの作成 > New-Item share-folder -ItemType Directory > cd share-folder # share-folderの監査エントリーの確認 > $path = "Z:\share-folder" > $ACL = Get-Acl -Path $path > $ACL | Format-List # 監査エントリーの追加及び、監査エントリーが正常に追加されているかを確認 > $AuditUser = "Everyone" > $AuditRules = "FullControl" > $InheritType = "ContainerInherit,ObjectInherit" > $AuditType = "Success,Failure" > $AccessRule = New-Object System.Security.AccessControl.FileSystemAuditRule($AuditUser,$AuditRules,$InheritType,"None",$AuditType) > $ACL.SetAuditRule($AccessRule) > Set-Acl -Path $path -AclObject $ACL > Get-Acl -Path $path -Audit | Format-List
コマンドを実行すると、以下のようにAudit
にEveryone Success, Failure FullControl
という情報があることから、正常に監査エントリ設定されたことが確認できます。
以上でログの設定は完了です。
この後は、イベントを発生させるため、Z:\share-folder
配下で、適当にフォルダーやファイルを作成・削除、データの追記などの操作を行いました。
ログの可視化
Kibanaの設定
いよいよログの可視化です。
ログの可視化をするにあたって、ログを可視化するために必要なダッシュボードやインデックスパターンを設定します。
設定はSIEM on Amazon ESが提供しているファイルをインポートして行います。インポートするファイルはこちらからダウンロードします。
ダウンロードしたファイルは解凍しておきます。
続いて、Kibanaにログインします。ログイン先のURLやID、パスワードは、AWS CDK実行時のログに出力されているので、そちらをご確認ください。
サンプルデータではなく、自分で収集したログを使いたいので、Explore on my own
をクリックします。
ユーザー専用のダッシュボード等を用意してカスタマイズしたいので、Private
を選択して、Confirm
クリックします。
左メニューからStack Management
をクリックします。
Saved Object
のImport
をクリックします。
解凍したフォルダ内のdashboard.ndjson
をアップロードし、Import
をクリックします。
インポートが完了したことを確認します。
ダッシュボードやインデックスパターンがインポートされたことが確認できます。
CloudTrailの可視化
それでは、CloudTrailのログを可視化してみます。
Dashboard
から、CloudTrail Summary
をクリックします。
すると、以下のようにCloudTrailのダッシュボードが表示され、接続元IPアドレスや、実行されたイベントなど様々な情報を確認することができます。イケてる感じで良いですね。
VPC Flow Logsの可視化
続いて、VPC Flow Logsのログを可視化してみます。
Dashboard
から、VPCFlowLogs Summary
をクリックします。
すると、以下のようにVPC Flow Logsのダッシュボードが表示され、どの時間帯にどのような通信が多かったのかなど様々な情報を確認することができます。
FSx for Windows File Serverのファイルアクセス監査ログの可視化
Discoverの表示
最後に、FSx for Windows File Serverのファイルアクセス監査ログを可視化します。
まず、そもそもElasticsearch Serviceにログが取り込まれているかを確認をします。
Discover
をクリックすると、取り込んだログの一覧を出力することができます。
53,540件もありますね。この中から、FSx for Windows File Serverのファイルアクセス監査ログのみ抽出するには、user.ini
で定義したevent.category
を使用します。
FSx for Windows File Serverのファイルアクセス監査ログのevent.category
はwindows
と定義しました。この条件で抽出をすると、以下のように、FSx for Windows File Serverのファイルアクセス監査ログのみ抽出することができました。
1つ1つのログは畳まれているので、展開してみます。展開すると以下のように、各フィールドと値が紐づいていることが確認できます。
このままだと、生のログを出しているだけです。より、条件を絞って情報を表示してみます。
以下の例では、イベントIDやアクセスリスト、ユーザー名、操作対象のオブジェクト名のみを抽出してみました。このように表示されると、いつ誰が、何を、どのような操作をしたのか確認しやすいですね。
インデックスパターンの作成
FSx for Windows File Serverのファイルアクセス監査ログもダッシュボードで良い感じに表示させるためには、どのフィールドが、どのようなType(型)なのかを定義する必要があります。そのための作業として、FSx for Windows File Serverのファイルアクセス監査ログのインデックスパターンを定義します。
左メニューから、Stack Management
を選択し、Index Patterns
のCreate index pattern
をクリックします。
インデックスパターンの名前を設定します。
FSx for Windows File Serverのファイルアクセス監査ログのインデックスパターン名(log-aws-fsx-windows-audit-*
)を入力し、Next Step
をクリックします。
次に、作成するインデックスパターンのtimeフィールドを設定します。
今回は、user.ini
でtimestamp_key
を使って、@timestamp
にイベントの発生時間を渡しているので、@timestamp
を選択します。選択後、Create index pattern
で、インデックスパターンを作成します。
すると、以下のようなインデックスパターンが作成されました。フィールド名やTypeは、今まで取り込んだログから自動で判断してくれます。
ダッシュボードの作成
最後にダッシュボードの作成です。
Dashboard
から、Create dashboard
をクリックします。
空のダッシュボードが作成されます。Create new
をクリックして、ダッシュボードにオブジェクトを追加します。
今回は、イベントIDの割合を表示させてみようと思います。割合を表示させるために、Pie
を選択します。
続いて、先ほど作成したインデックスパターンlog-aws-fsx-windows-audit-*
を選択します。
その後は、対象のフィールドや表示させる数などを設定します。最後に、Update
をクリックすることで、以下のようなイベントID毎の割合を表示するオブジェクトが作成されます。作成後は忘れずに、Save
もクリックしましょう。
ダッシュボードにも先ほど作成したオブジェクトが追加されていることが確認できます。
他にもダッシュボードに色々なオブジェクトを追加してみました。
ダッシュボードを作成すると、イベント発生時刻やイベントID、ユーザー名を絞って、簡単に全体を把握することができます。
ログはダッシュボードで可視化するに限る
FSx for Windows File Serverのファイルアクセス監査ログやCloudTrail、VPC Flow LogsをSIEM on Amazon ESで可視化してみました。
ダッシュボードでログを確認できるようになると、どのような事象が発生しているのかが分かりやすくなることはもちろん、なんだかテンションも上がりますよね。
SIEM on Amazon ESを使えば、非常に簡単にログの分析基盤を作成することができるので、
- 今までログは取っているけど、イマイチ活用できていない
- 一つの画面で様々な情報を見比べながら調査をしたい
- セキュリティインシデント発生時の調査をもっと簡単にしたい
といった要望・課題に対してうってつけのソリューションだと思います。
この記事が誰かの助けになれば幸いです。
以上、AWS事業本部 コンサルティング部の のんピ(@non____97)でした!